use std::fmt;
use crate::html_node::YsNode;


#[derive(Debug)]
pub enum ParseError {
    // 该解析器无法解析该节点
    UnSupportedNode(String),
    IoError(std::io::Error),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ParseError::IoError(err) => write!(f, "IO错误: {}", err),
            ParseError::UnSupportedNode(tag) => write!(f, "无法解析的节点: {}", tag),
        }
    }
}

impl std::error::Error for ParseError {}

impl From<std::io::Error> for ParseError {
    fn from(err: std::io::Error) -> Self {
        ParseError::IoError(err)
    }
}


pub trait HtmlToMarkdownHandler {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError>;
}


// 普通文本解析器
pub struct TextParser;
impl HtmlToMarkdownHandler for TextParser {
    fn handle(&self, node: &YsNode, _: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        match node.get_text() {
            Some(text) => Ok(text),
            None => Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()))
        }
    }
}

// Heading解析器
pub struct HeadingParser;
impl HtmlToMarkdownHandler for HeadingParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        let tag = node.get_tag().unwrap_or_default();
        if let Some(level) = tag.strip_prefix('h').and_then(|s| s.parse::<u32>().ok()).filter(|&l| l > 0 && l <= 6) {
            let default_parser = DefaultParser::new();
            let text = default_parser.handle(node, handler)?;
            Ok(format!("{} {}\n\n", "#".repeat(level as usize), text))
        } else {
            Err(ParseError::UnSupportedNode(tag))
        }
    }
}


// 图片解析器
pub struct ImageParser;
impl HtmlToMarkdownHandler for ImageParser {
    fn handle(&self, node: &YsNode, _: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() != Some("img") {
            return Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()));
        }
        let attrs = node.get_attributes();
        let src = attrs.get("src").unwrap_or(&String::new()).clone();
        let alt = attrs.get("alt").unwrap_or(&String::new()).clone();
        Ok(format!("![{}]({})\n\n", alt, src))
    }
}

// 链接解析器
pub struct LinkParser;
impl HtmlToMarkdownHandler for LinkParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() != Some("a") {
            return Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()));
        }
        let attrs = node.get_attributes();
        let href = attrs.get("href").map(String::as_str).unwrap_or("");
        let default_parser = DefaultParser::new();
        let text = default_parser.handle(node, handler).unwrap();
        Ok(format!("[{}]({})", text, href))
    }
}

// 段落解析器
pub struct ParagraphParser;
impl HtmlToMarkdownHandler for ParagraphParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() != Some("p") {
            return Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()));
        }
        let default_parser = DefaultParser::new();
        let text = default_parser.handle(node, handler).unwrap();
        Ok(format!("{}\n\n", text))
    }
}

// 数字列表解析器
pub struct ListParser;
impl HtmlToMarkdownHandler for ListParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() != Some("ul") && node.get_tag().as_deref() != Some("ol") {
            return Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()));
        }
        
        let default_parser = DefaultParser::new();
        let children = node.get_children_elements();
        let mut index = 1;
        let items = children.iter()
            .filter(|child| child.get_tag().as_deref() == Some("li"))
            .map(move|child| {
                let text = default_parser.handle(child, handler).unwrap();
                // 如果child是ol，则生成序号，如果child是ul，则返回-
                let prefix = if node.get_tag().as_deref() == Some("ol") {
                    let current_index = index;
                    index += 1;
                    format!("{}.", current_index)
                } else {
                    "-".to_string()
                };
            format!("{} {}", prefix, text.trim())
        }).collect::<Vec<String>>().join("\n");
        Ok(format!("{}\n\n", items))
    }
}

// 斜体和粗体解析器
pub struct EmphasisParser {
    bold_tag: String,
    italic_tag: String,
}
impl EmphasisParser {
    pub fn new() -> Self {
        EmphasisParser { bold_tag: "strong".to_string(), italic_tag: "em".to_string() }
    }
    pub fn new_with_tag(bold_tag: String, italic_tag: String) -> Self {
        EmphasisParser { bold_tag, italic_tag }
    }
}
impl HtmlToMarkdownHandler for EmphasisParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() != Some(&self.italic_tag) && node.get_tag().as_deref() != Some(&self.bold_tag) {
            return Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()));
        }
        let default_parser = DefaultParser::new();
        let text = default_parser.handle(node, handler).unwrap();
        let tag = node.get_tag().unwrap_or_default();
        let prefix = if tag == self.italic_tag {
            "*"
        } else {
            "**"
        };
        Ok(format!("{}{}{}", prefix, text, prefix))
    }
}


// 分割线解析器
pub struct HrParser;
impl HtmlToMarkdownHandler for HrParser {
    fn handle(&self, node: &YsNode, _: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() == Some("hr") {
            Ok("\n---\n".to_string())
        } else {
            Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()))
        }
    }
}

// inline code解析器
pub struct CodeInlineParser;
impl HtmlToMarkdownHandler for CodeInlineParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() == Some("code") {
            let default_parser = DefaultParser::new();
            let text = default_parser.handle(node, handler).unwrap();
            Ok(format!("`{}`", text))
        } else {
            Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()))
        }
    }
}

// 代码块解析器
pub struct CodeBlockParser;
impl HtmlToMarkdownHandler for CodeBlockParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        if node.get_tag().as_deref() == Some("pre") {
            let default_parser = DefaultParser::new_with_whitespace(); 
            let children = node.get_children_raw();
            let child = children.get(0).unwrap();
            let text = default_parser.handle(child, handler).unwrap();
            Ok(format!("\n```\n{}\n```\n\n", text.trim()))
        } else {
            Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()))
        }
    }
}

// 默认解析器
pub struct DefaultParser {
    // 是否忽略空白字符
    ignore_whitespace: bool,
}
impl DefaultParser {
    pub fn new() -> Self {
        DefaultParser { ignore_whitespace: true }
    }
    pub fn new_with_whitespace() -> Self {
        DefaultParser { ignore_whitespace: false }
    }
}
impl HtmlToMarkdownHandler for DefaultParser {
    fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
        // 检查node有没有子节点，如果有，则递归调用handler，将所有子节点转换为markdown
        let children = node.get_children_raw();
        if children.is_empty() {
            return Ok(node.get_text().unwrap_or_default());
        }
        let text = children.iter()
            .map(|child| {
                let result = handler.handle(child, handler).unwrap();
                // 如果ignore_whitespace为true，并且child是text节点，则去掉result两端的空白字符
                if self.ignore_whitespace && child.is_text_node() {
                    result.trim().to_string()
                } else {
                    result
                }
            })
            .collect::<Vec<String>>()
            .join("");
        Ok(text)
    }
}

// 创建一个跳过解析器, 如果skip_condition返回true，则跳过该节点
pub fn make_skip_parser(skip_condition: Box<dyn Fn(&YsNode) -> bool + 'static>) -> impl HtmlToMarkdownHandler {
    struct SkipParser {
        skip_condition: Box<dyn Fn(&YsNode) -> bool + 'static>,
    }
    impl HtmlToMarkdownHandler for SkipParser {
        fn handle(&self, node: &YsNode, _: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
            if (self.skip_condition)(node) {
                Ok(String::new())
            } else {
                Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()))
            }
        }
    }
    SkipParser { skip_condition: Box::new(skip_condition) }
}

// 打包解析器
pub fn make_markdown_pack_parser() -> impl HtmlToMarkdownHandler {
    let parsers:Vec<Box<dyn HtmlToMarkdownHandler>> = vec![
        Box::new(HeadingParser),
        Box::new(ImageParser),
        Box::new(LinkParser),
        Box::new(TextParser),
        Box::new(ParagraphParser),
        Box::new(ListParser),
        Box::new(EmphasisParser::new()),
        Box::new(HrParser),
        Box::new(CodeInlineParser),
        Box::new(CodeBlockParser),
        Box::new(DefaultParser::new())
    ];
    combine_markdown_parser(parsers)
}

pub fn combine_markdown_parser(parsers: Vec<Box<dyn HtmlToMarkdownHandler>>) -> impl HtmlToMarkdownHandler {
    struct DefaultParser {
        parsers: Vec<Box<dyn HtmlToMarkdownHandler>>,
    }
    impl DefaultParser {
        fn new(parsers: Vec<Box<dyn HtmlToMarkdownHandler>>) -> Self {
            DefaultParser { parsers }
        }
    }
    impl HtmlToMarkdownHandler for DefaultParser {
        fn handle(&self, node: &YsNode, handler: &dyn HtmlToMarkdownHandler) -> Result<String, ParseError> {
            // 依次调用parsers中的解析器，如果解析器返回OK，则返回OK，如果解析器返回UnSupportedNode，则继续下一个解析器，否则返回错误
            for parser in &self.parsers {
                let result = parser.handle(node, handler);
                match result {
                    Ok(text) => return Ok(text),
                    Err(ParseError::UnSupportedNode(_)) => continue,
                    Err(e) => return Err(e),
                }
            }
            // 如果没有任何解析器匹配，则抛出该解析器无法解析的错误
            Err(ParseError::UnSupportedNode(node.get_tag().unwrap_or_default().to_string()))
        }
    }
    DefaultParser::new(parsers)
}
